# Python3 迭代器与生成器
## 迭代器
'''
迭代是Python最强大的功能之一，是访问集合元素的一种方式。
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问，直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法：iter() 和 next()。
'''
### 字符串，列表或元组对象都可用于创建迭代器：
list = [1, 2, 3, 4]
it = iter(list)
for i in range(len(list)):
    print(next(it), end=", ")
print("")
### 迭代器对象也可以使用常规for语句进行遍历：
it2 = iter(list)
for x in it2:
    print(x, end=", ")
print("")
### while 循环遍历
import sys  # 引入 sys 模块
it3 = iter(list)
while True:
    try:
        print(next(it3), end=", ")
    except StopIteration: # StopIteration异常，表示 迭代器没有更多的值
        print("结束了~")
        break #sys.exit()
'''
sys.exit()会引发一个异常：SystemExit，如果这个异常没有被捕获，那么python解释器将会退出。
如果有捕获此异常的代码，那么这些代码还是会执行。捕获这个异常可以做一些额外的清理工作。
0为正常退出，其他数值（1-127）为不正常，可抛异常事件供捕获。
os._exit()也可以退出程序，但它会直接将python解释器退出，余下的语句不会执行。
os._exit() 多用于在子线程中退出，sys.exit() 多用于在主线程中退出。
'''
print('------------------------------')

## 创建一个迭代器
'''
把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。
类都有一个构造函数，Python 的构造函数为 __init__(), 它会在对象初始化的时候执行。
__iter__() 方法返回一个特殊的迭代器对象， 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
__next__() 方法（Python 2 里是 next()）会返回下一个迭代器对象。
'''
### 创建一个返回数字的迭代器，初始值为 1，逐步递增 1：
class MyNumbers:
    def __iter__(self):
        self.a = 1
        return self
    def __next__(self):
        if self.a <= 20:
            x = self.a
            self.a += 1
            return x
        else:
            raise StopIteration
'''
StopIteration 异常：用于标识迭代的完成，防止出现无限循环的情况，
在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
'''
testnum = MyNumbers()
numit = iter(testnum)
print(next(numit))
print(next(numit))
print(next(numit))
print(next(numit))
print(next(numit))
numit = iter(testnum)
for x in numit:
    print(x, end=", ")
print("")
print('------------------------------')

## 生成器
'''
在 Python 中，使用了 yield 的函数被称为生成器（generator）。
跟普通函数不同的是，生成器是一个返回迭代器的函数，只能用于迭代操作，更简单点理解生成器就是一个迭代器。
在调用生成器运行的过程中，每次遇到 yield 时函数会暂停并保存当前所有的运行信息，返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
调用一个生成器函数，返回的是一个迭代器对象。
'''
### 以下实例使用 yield 实现斐波那契数列：
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n):
            return
        yield b
        a, b = b, a + b
        counter += 1

f = fibonacci(10) # f 是一个迭代器，由生成器返回生成
for x in f:
    print(x, end=", ")
print("")
print('------------------------------')